//
//  WCAImageDownloader.m
//  WeChatAssistant
//
//  Created by Guo Rui on 2017/11/24.
//  Copyright © 2017年 GR Harry. All rights reserved.
//

#import "WCAImageDownloader.h"
#import "NSData+ImageContentType.h"

@interface WCAImageDownloader()
@property (strong, nonatomic) NSCache *memoryCache;

@property (strong, nonatomic) NSMutableDictionary *dataTasks;
@property (strong, nonatomic) NSMutableDictionary *completionBlocks;

@property (strong, nonatomic) dispatch_queue_t safe_operation_queue;

@property (strong, nonatomic) NSURLSession *session;
@property (copy, nonatomic) NSString *cachePath;
@end

@implementation WCAImageDownloader

+ (instancetype)sharedInstance
{
    static WCAImageDownloader *downloader = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        downloader = [[WCAImageDownloader alloc] init];
    });
    return downloader;
}
#pragma mark - Getter
- (NSMutableDictionary *)dataTasks
{
    if (!_dataTasks) {
        _dataTasks = [NSMutableDictionary dictionaryWithCapacity:0];
    }
    return _dataTasks;
}

- (NSMutableDictionary *)completionBlocks
{
    if (!_completionBlocks) {
        _completionBlocks = [NSMutableDictionary dictionaryWithCapacity:0];
    }
    return _completionBlocks;
}

- (NSCache *)memoryCache
{
    if (!_memoryCache) {
        _memoryCache = [[NSCache alloc] init];
        _memoryCache.totalCostLimit = 30;
    }
    return _memoryCache;
}

- (NSURLSession *)session
{
    if (!_session) {
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    }
    return _session;
}

- (dispatch_queue_t)safe_operation_queue
{
    if (!_safe_operation_queue) {
        _safe_operation_queue = dispatch_queue_create("cn.timeface.wechatassistant.imagedownloader.safe_operation_queue", NULL);
    }
    return _safe_operation_queue;
}

- (NSString *)cachePath
{
    if (!_cachePath) {
        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        NSString *folderPath = [caches stringByAppendingPathComponent:@"imageCache"];
        NSFileManager *fileMag = [NSFileManager defaultManager];
        if (![fileMag fileExistsAtPath:folderPath]) {
            [fileMag createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];
        }
        _cachePath = folderPath;
    }
    return _cachePath;
}

#pragma mark - Private
- (void)sendWithUrl:(NSString *)url image:(UIImage *)image error:(NSError *)error
{
    dispatch_async(self.safe_operation_queue, ^{
        WCAImageDownloadCompletion completion = [self.completionBlocks objectForKey:url];
        if (completion) {
            completion(image, error);
        }
    });
}

- (UIImage *)diskCacheForUrl:(NSString *)url
{
    url = [url stringByReplacingOccurrencesOfString:@"/" withString:@""];
    NSString *fullPath = [self.cachePath stringByAppendingPathComponent:[url lastPathComponent]];
    
    NSData *imageData = [NSData dataWithContentsOfFile:fullPath];
    return [UIImage imageWithData:imageData];
}

- (void)setDiskCacheWithImageData:(NSData *)imageData url:(NSString *)url
{
    url = [url stringByReplacingOccurrencesOfString:@"/" withString:@""];
    NSString *fullPath = [self.cachePath stringByAppendingPathComponent:[url lastPathComponent]];
    BOOL success = [imageData writeToFile:fullPath atomically:YES];
    if (success) {
        NSLog(@"saveDiskCacheSuccess");
    }
}

#pragma mark - Public

- (void)cacelWithURL:(NSString *)url
{
    dispatch_async(self.safe_operation_queue, ^{
        NSURLSessionDataTask *dataTask = [self.dataTasks objectForKey:url];
        if (dataTask) {
            [dataTask cancel];
            [self.dataTasks removeObjectForKey:url];
            [self.completionBlocks removeObjectForKey:url];
        }
    });
}

- (void)downloadWithURL:(NSString *)url completionBlock:(WCAImageDownloadCompletion)completion
{
    if (url == nil || url.length == 0) {
        if (completion) {
            NSError *error = [NSError errorWithDomain:@"WCAError_Domain" code:1 userInfo:nil];
            completion(nil, error);
        }
        return;
    }
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
        __weak WCAImageDownloader * weakself = self;
        [self addCompletedBlock:completion forURL:url createCallback:^{
            // 判断内存缓存
            UIImage *image = [weakself.memoryCache objectForKey:url];
            if (image) {
                NSLog(@"------------------------------------ 内存");
                [weakself sendWithUrl:url image:image error:nil];
                return;
            }
            
            // 判断磁盘缓存
            image = [self diskCacheForUrl:url];
            if (image) {
                NSLog(@"------------------------------------ 磁盘");
                [weakself.memoryCache setObject:image forKey:url cost:2];
                [weakself sendWithUrl:url image:image error:nil];
                return;
            }
            
            // 进行请求
            NSURLSessionDataTask *dataTask = [weakself.session dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                NSLog(@"------------------------------------ requeset");
                if (error) {
                    NSLog(@"error -- %@", url);
                    [weakself sendWithUrl:url image:nil error:error];
                }
                else {
                    if (data) {
                        UIImage *img = [UIImage imageWithData:data];
                        [weakself.memoryCache setObject:img forKey:url cost:2];
                        [weakself setDiskCacheWithImageData:data url:url];
                        [weakself sendWithUrl:url image:img error:nil];
                    }
                }
                
                dispatch_async(weakself.safe_operation_queue, ^{
                    [weakself.dataTasks removeObjectForKey:url];
                    [weakself.completionBlocks removeObjectForKey:url];
                });
            }];
            
            [dataTask resume];
            
            dispatch_async(weakself.safe_operation_queue, ^{
                [weakself.dataTasks setObject:dataTask forKey:url];
            });
        }];
    });
}

- (void)addCompletedBlock:(WCAImageDownloadCompletion)completedBlock
                     forURL:(NSString *)url
             createCallback:(void(^)(void))createCallback
{
    __block NSURLSessionDataTask *dataTask = nil;
    dispatch_async(self.safe_operation_queue, ^{
        dataTask = [self.dataTasks objectForKey:url];
    });
    
    if (!dataTask) {
        if (createCallback) {
            dispatch_async(self.safe_operation_queue, ^{
                [self.completionBlocks setObject:completedBlock forKey:url];
            });
            createCallback();
        }
    }
}

@end
